{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Description of VGG16 model\n",
    "VGG16 (also called OxfordNet) is a convolutional neural network architecture named after the Visual Geometry Group from Oxford, who developed it.\n",
    "It was used to win the ILSVR (ImageNet) competition in 2014.\n",
    "To this day is it still considered to be an excellent vision model, although it has been somewhat outperformed by more revent advances such as Inception and ResNet.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "original_dataset_dir = \"train\"\n",
    "base_dir = 'cats_and_dogs_small'\n",
    "train_dir = os.path.join(base_dir, 'train')\n",
    "validation_dir = os.path.join(base_dir, 'validation')\n",
    "test_dir = os.path.join(base_dir, 'test')\n",
    "print(train_dir)\n",
    "print(validation_dir)\n",
    "print(test_dir)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tensorflow.keras.applications import VGG16\n",
    "conv_base = VGG16(weights='imagenet',include_top=False,\n",
    "                  input_shape=(150, 150, 3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "vgg16 (Model)                (None, 4, 4, 512)         14714688  \n",
      "_________________________________________________________________\n",
      "flatten (Flatten)            (None, 8192)              0         \n",
      "_________________________________________________________________\n",
      "dense (Dense)                (None, 256)               2097408   \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 1)                 257       \n",
      "=================================================================\n",
      "Total params: 16,812,353\n",
      "Trainable params: 16,812,353\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "from tensorflow.keras import models\n",
    "from tensorflow.keras import layers\n",
    "\n",
    "model = models.Sequential()\n",
    "model.add(conv_base)\n",
    "model.add(layers.Flatten())\n",
    "model.add(layers.Dense(256, activation='relu'))\n",
    "model.add(layers.Dense(1, activation='sigmoid'))\n",
    "\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# freezing the convolutional base\n",
    "In Keras, you freeze a network by setting its trainable attribute to False:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This is the number of trainable weights before freezing the conv base: 30\n"
     ]
    }
   ],
   "source": [
    "print('This is the number of trainable weights ''before freezing the conv base:', len(model.trainable_weights))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This is the number of trainable weights after freezing the conv base: 4\n"
     ]
    }
   ],
   "source": [
    "conv_base.trainable = False\n",
    "print('This is the number of trainable weights ''after freezing the conv base:', len(model.trainable_weights))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Training the model end to end with a frozen convolutional base"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tensorflow.keras.preprocessing.image import ImageDataGenerator\n",
    "\n",
    "train_datagen = ImageDataGenerator(\n",
    "                rescale=1./255,\n",
    "                rotation_range=40,\n",
    "                width_shift_range=0.2,\n",
    "                height_shift_range=0.2,\n",
    "                shear_range=0.2,\n",
    "                zoom_range=0.2,\n",
    "                horizontal_flip=True,\n",
    "                fill_mode='nearest')\n",
    "\n",
    "test_datagen = ImageDataGenerator(rescale=1./255)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 2000 images belonging to 2 classes.\n"
     ]
    }
   ],
   "source": [
    "train_generator = train_datagen.flow_from_directory(\n",
    "                    train_dir,\n",
    "                    target_size=(150, 150),\n",
    "                    batch_size=20,\n",
    "                    class_mode='binary')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 1000 images belonging to 2 classes.\n"
     ]
    }
   ],
   "source": [
    "validation_generator = test_datagen.flow_from_directory(\n",
    "                        validation_dir,\n",
    "                        target_size=(150, 150),\n",
    "                        batch_size=20,\n",
    "                        class_mode='binary')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tensorflow.keras import optimizers\n",
    "model.compile(loss='binary_crossentropy',\n",
    "                optimizer=optimizers.RMSprop(lr=2e-5),\n",
    "                metrics=['acc'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/30\n",
      "2/2 [==============================] - 16s 8s/step - loss: 0.6881 - acc: 0.5500 - val_loss: 0.6453 - val_acc: 0.6350\n",
      "Epoch 2/30\n",
      "2/2 [==============================] - 15s 8s/step - loss: 0.6567 - acc: 0.6500 - val_loss: 0.6375 - val_acc: 0.6380\n",
      "Epoch 3/30\n",
      "2/2 [==============================] - 15s 8s/step - loss: 0.6481 - acc: 0.6000 - val_loss: 0.6289 - val_acc: 0.6620\n",
      "Epoch 4/30\n",
      "2/2 [==============================] - 15s 8s/step - loss: 0.6966 - acc: 0.5750 - val_loss: 0.6213 - val_acc: 0.6870\n",
      "Epoch 5/30\n",
      "2/2 [==============================] - 16s 8s/step - loss: 0.5728 - acc: 0.7750 - val_loss: 0.6185 - val_acc: 0.6570\n",
      "Epoch 6/30\n",
      "2/2 [==============================] - 15s 8s/step - loss: 0.6249 - acc: 0.6500 - val_loss: 0.6131 - val_acc: 0.6810\n",
      "Epoch 7/30\n",
      "2/2 [==============================] - 15s 8s/step - loss: 0.6441 - acc: 0.6500 - val_loss: 0.6013 - val_acc: 0.7040\n",
      "Epoch 8/30\n",
      "2/2 [==============================] - 15s 8s/step - loss: 0.6722 - acc: 0.6000 - val_loss: 0.5942 - val_acc: 0.7140\n",
      "Epoch 9/30\n",
      "2/2 [==============================] - 15s 8s/step - loss: 0.5892 - acc: 0.8000 - val_loss: 0.5858 - val_acc: 0.7280\n",
      "Epoch 10/30\n",
      "2/2 [==============================] - 15s 8s/step - loss: 0.6410 - acc: 0.6000 - val_loss: 0.5884 - val_acc: 0.7000\n",
      "Epoch 11/30\n",
      "2/2 [==============================] - 16s 8s/step - loss: 0.6040 - acc: 0.7000 - val_loss: 0.5750 - val_acc: 0.7410\n",
      "Epoch 12/30\n",
      "2/2 [==============================] - 16s 8s/step - loss: 0.4936 - acc: 0.9250 - val_loss: 0.5809 - val_acc: 0.6940\n",
      "Epoch 13/30\n",
      "2/2 [==============================] - 16s 8s/step - loss: 0.6565 - acc: 0.5750 - val_loss: 0.5606 - val_acc: 0.7510\n",
      "Epoch 14/30\n",
      "2/2 [==============================] - 16s 8s/step - loss: 0.5603 - acc: 0.7500 - val_loss: 0.5708 - val_acc: 0.7040\n",
      "Epoch 15/30\n",
      "2/2 [==============================] - 16s 8s/step - loss: 0.5796 - acc: 0.7250 - val_loss: 0.5518 - val_acc: 0.7470\n",
      "Epoch 16/30\n",
      "2/2 [==============================] - 18s 9s/step - loss: 0.6556 - acc: 0.5750 - val_loss: 0.5459 - val_acc: 0.7660\n",
      "Epoch 17/30\n",
      "2/2 [==============================] - 18s 9s/step - loss: 0.5795 - acc: 0.7750 - val_loss: 0.5404 - val_acc: 0.7650\n",
      "Epoch 18/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.5924 - acc: 0.7250 - val_loss: 0.5330 - val_acc: 0.7760\n",
      "Epoch 19/30\n",
      "2/2 [==============================] - 18s 9s/step - loss: 0.5151 - acc: 0.8750 - val_loss: 0.5272 - val_acc: 0.7860\n",
      "Epoch 20/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.6180 - acc: 0.6250 - val_loss: 0.5285 - val_acc: 0.7700\n",
      "Epoch 21/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.5268 - acc: 0.7000 - val_loss: 0.5208 - val_acc: 0.7810\n",
      "Epoch 22/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.5238 - acc: 0.8250 - val_loss: 0.5151 - val_acc: 0.7860\n",
      "Epoch 23/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.6148 - acc: 0.7500 - val_loss: 0.5160 - val_acc: 0.7790\n",
      "Epoch 24/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.5961 - acc: 0.7250 - val_loss: 0.5158 - val_acc: 0.7750\n",
      "Epoch 25/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.5928 - acc: 0.6750 - val_loss: 0.5153 - val_acc: 0.7720\n",
      "Epoch 26/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.5491 - acc: 0.7500 - val_loss: 0.5095 - val_acc: 0.7790\n",
      "Epoch 27/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.6065 - acc: 0.6500 - val_loss: 0.5150 - val_acc: 0.7560\n",
      "Epoch 28/30\n",
      "2/2 [==============================] - 18s 9s/step - loss: 0.5093 - acc: 0.8750 - val_loss: 0.4966 - val_acc: 0.7960\n",
      "Epoch 29/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.5864 - acc: 0.6750 - val_loss: 0.4926 - val_acc: 0.8020\n",
      "Epoch 30/30\n",
      "2/2 [==============================] - 17s 9s/step - loss: 0.5579 - acc: 0.7500 - val_loss: 0.4975 - val_acc: 0.7810\n"
     ]
    }
   ],
   "source": [
    "history = model.fit_generator(\n",
    "                train_generator,\n",
    "                steps_per_epoch=2, #100\n",
    "                epochs=30,\n",
    "                validation_data=validation_generator,\n",
    "                validation_steps=50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "conda_gpu",
   "language": "python",
   "name": "conda_gpu"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
